Untersuchung eines IMDB Datensatzes¶

In dieser Untersuchung wird ein IMDB Datensatz analysiert. Dabei werden verschiedene Fragen beantwortet, um Einblicke in die Bewertungen von Filmen zu gewinnen.

Unter anderem werden folgende Fragen beantwortet.

  • Gibt es besonders gut bewertete Film Genres?
  • Sind ältere Filme beliebter als neuere?
  • Wie wirken sich das Veröffentlichungsjahr des Films und das Genre auf die Bewertungen aus?
  • Gibt es Länder, deren Filme durchschnittlich besonders gut bewertet werden?

Erwartungshaltung: Unsere Erwartungshaltung ist, dass bestimmte Film Genres besser bewertet wurden als andere. Zum Beispiel könnten Action-Filme höhere Bewertungen erhalten als Horrorfilme oder Komödien. Außerdem nehmen wir an, dass ältere Filme besser bewertet wurden, da die Menschen damals nicht so hohe Erwartungen an Filme hatten wie heute. Es könnte auch sein, dass ältere Filme aufgrund ihrer historischen Bedeutung oder ihres kulturellen Einflusses höhere Bewertungen erhalten. Man könnte ebenso annehmen, dass Filme aus bestimmten Ländern durchschnittlich höhere Bewertungen erhalten als Filme aus anderen Ländern. Dies könnte auf kulturelle Unterschiede in der Filmproduktion und im Geschmack des Publikums zurückzuführen sein. Es ist auch möglich, dass Filme aus Ländern mit einer starken Filmindustrie, wie den USA oder Indien, durchschnittlich höhere Bewertungen erhalten als Filme aus Ländern mit einer weniger entwickelten Filmindustrie.

Um diese Fragen zu beantworten, werden wir den IMDB Datensatz analysieren und verschiedene statistische Methoden anwenden. Wir werden auch versuchen, Trends und Muster in den Daten zu identifizieren. Im Laufe des Projekts haben wir auch weitergehende Fragestellungen im Bezug auf das Thema der Untersuchung von imdb Daten untersucht. Einerseits haben wir einen eigenen Datensatz erstellt und analysiert, indem wir über eine Library direkt auf IMDB-Daten zugegriffen haben, die wir für unsere Fragestellung benötigt haben. Andererseits haben wir eine umfassende Sentiment-Analyse für IMDB-Kommentare durchgeführt, die modellspezifisches Preprocessing, Training und Evaluierung umfasst.

Importing the necessary libraries for data visualization and analysis

In [ ]:
import seaborn as sns # Seaborn is a data visualization library based on matplotlib, provides beautiful default styles and color palettes
import matplotlib.pyplot as plt # Matplotlib is a data visualization library in Python, used to create interactive plots and charts
import pandas as pd # Pandas is a library for data manipulation and analysis
import numpy as np # NumPy is a library for the Python programming language, adding support for large, multi-dimensional arrays and matrices

Reading the movie data from a CSV file into a pandas dataframe

In [ ]:
#Reading the movie data from a CSV file into a pandas dataframe
df = pd.read_csv('movies_initial.csv')

#Filtering out movies with less than 1000 votes on IMDB
df = df[df["imdbVotes"] >= 1000]

#Displaying the head of the filtered dataframe
df.head()
Out[ ]:
imdbID title year rating runtime genre released director writer cast ... imdbRating imdbVotes poster plot fullplot language country awards lastupdated type
0 1 Carmencita 1894 NOT RATED 1 min Documentary, Short NaN William K.L. Dickson NaN Carmencita ... 5.9 1032.0 https://m.media-amazon.com/images/M/MV5BMjAzND... Performing on what looks like a small wooden s... Performing on what looks like a small wooden s... NaN USA NaN 2015-08-26 00:03:45.040000000 movie
1 5 Blacksmith Scene 1893 UNRATED 1 min Short 1893-05-09 William K.L. Dickson NaN Charles Kayser, John Ott ... 6.2 1189.0 NaN Three men hammer on an anvil and pass a bottle... A stationary camera looks at a large anvil wit... NaN USA 1 win. 2015-08-26 00:03:50.133000000 movie
4 10 Employees Leaving the Lumi�re Factory 1895 NaN 1 min Documentary, Short 1895-03-22 Louis Lumi�re NaN NaN ... 6.9 3469.0 NaN A man opens the big gates to the Lumi�re facto... A man opens the big gates to the Lumi�re facto... NaN France NaN 2015-08-26 00:03:56.603000000 movie
5 12 The Arrival of a Train 1896 NaN 1 min Documentary, Short 1896-01-01 Auguste Lumi�re, Louis Lumi�re NaN NaN ... 7.3 5043.0 https://m.media-amazon.com/images/M/MV5BMjEyND... A group of people are standing in a straight l... A group of people are standing in a straight l... NaN France NaN 2015-08-15 00:02:53.443000000 movie
6 14 Tables Turned on the Gardener 1895 NaN 1 min Comedy, Short NaN Louis Lumi�re NaN Fran�ois Clerc, Beno�t Duval ... 7.1 2554.0 NaN A gardener is watering his flowers, when a mis... A gardener is watering his flowers, when a mis... NaN France NaN 2015-08-12 00:06:18.237000000 movie

5 rows × 21 columns

Generating descriptive statistics for the filtered movie dataset

In [ ]:
df.describe() #This function provides a statistical summary of the numerical columns in the dataframe, including count, mean, standard deviation, minimum and maximum values, as well as percentiles
Out[ ]:
imdbID metacritic imdbRating imdbVotes
count 2.214200e+04 7692.000000 22142.000000 2.214200e+04
mean 6.323814e+05 56.598284 6.496712 2.322801e+04
std 8.107426e+05 18.004372 1.182726 6.790026e+04
min 1.000000e+00 1.000000 1.200000 1.000000e+03
25% 8.884775e+04 44.000000 5.800000 1.805000e+03
50% 2.391470e+05 57.000000 6.700000 3.831000e+03
75% 1.029130e+06 70.000000 7.300000 1.311800e+04
max 4.727512e+06 100.000000 9.600000 1.521105e+06

Checking the data types of each column in the dataframe

In [ ]:
df.dtypes #This function returns the data type of each column in the dataframe, which is useful for checking whether any columns need to be converted to a different data type before further analysis or visualization.
Out[ ]:
imdbID           int64
title           object
year            object
rating          object
runtime         object
genre           object
released        object
director        object
writer          object
cast            object
metacritic     float64
imdbRating     float64
imdbVotes      float64
poster          object
plot            object
fullplot        object
language        object
country         object
awards          object
lastupdated     object
type            object
dtype: object

Year sollte ein integer-Wert sein

In [ ]:
#PrePro
import re
df['year'] = df['year'].apply(lambda x: re.sub('[^0-9]', '', x))
df["year"] = df["year"].str[:4]
df['year'] = df['year'].astype(int)
df["year"].value_counts()
Out[ ]:
year
2009    931
2013    895
2011    890
2008    888
2012    886
       ... 
1901      1
1888      1
1893      1
1913      1
1904      1
Name: count, Length: 121, dtype: int64

Remove wrong formatted year columns and years with a very small amount of movies

In [ ]:
#PrePro
df = df.where(df["year"]>=1945)
df = df.where(df["year"]<=2016)

Visualizing the number of missing values in each column of the movie dataset

In [ ]:
# In this code cell, we use Seaborn and Matplotlib libraries to visualize the number of missing values in each column of the filtered movie dataset.

import seaborn as sns  
import matplotlib.pyplot as plt 
# Counting the number of missing values in each column of the dataframe

missing_vals = df.isnull().sum()

# Creating a bar plot to show the number of missing values in each column

fig, ax = plt.subplots(figsize=(10, 5))
ax = sns.barplot(x=missing_vals.index, y=missing_vals.values)

# Adding labels and title to the plot

plt.xlabel('Columns')
plt.ylabel('Number of Missing Values')
plt.title('Number of Missing Values in each Column')

# Rotating the x-axis labels to improve readability

for item in ax.get_xticklabels():
    item.set_rotation(70)

# Displaying the plot

plt.show()

EXKURS

Da dies ein Datensatz ist, welches auf Kaggle zu Data Analysis Zwecken zu Verfügung gestellt wurde, sind hier viele der Datenpunkte schon relativ sauber und nicht viel Preprocessing ist nötig. Trotzdem werden innerhalb dieses Notebooks immer wieder Preprocessing Schritte vorm Erstellen von Plots durchgeführt. Diese sind mit #PrePro gekennzeichnet. Um ein ausführliches Preprocessing durchführen zu können, wurde unter sentiment_analysis eine komplette Stimmungsanalyse von ImdB-Kommentaren durchgeführt.Das Preprocessing ist in "sentiment_analysis_preprocessing" zu finden. Die Modelle (Transformer (DistilBERT), NN, LSTM, Naive Bayes, Logistic Regression,SVM und Random Forest) sind in den restlichen Notebooks auf die Aufgabenstellung angewendet worden

Data Visualization: Unique Values in Movie Dataset

In [ ]:
# Counting the number of unique values in each column of the dataframe

unique_vals = df.nunique()

# Creating a horizontal bar plot to show the number of unique values in each column

fig, ax = plt.subplots(figsize=(10, 5))
ax = sns.barplot(x=unique_vals.values, y=unique_vals.index, orient='horizontal')

# Setting the x-axis scale to logarithmic scale for improved visualization

ax.set_xscale('log')

# Adding labels and title to the plot

plt.ylabel('Columns')
plt.xlabel('Number of Unique Values (log scale)')
plt.title('Number of Unique Values in each Column')

# Displaying the plot

plt.show()

Data Visualization: Distribution of IMDB Ratings

Als erstes erfolgt eine Untersuchung der Ratings im allgemeinen.

In [ ]:
# Selecting the rows where 'imdbRating' column is not null
df_filt = df[df['imdbRating'].notnull()]

# Creating a figure with a larger width
fig, ax = plt.subplots(figsize=(10, 5))

# Plotting the distribution of the 'imdb_rating' column using Seaborn's histplot function
sns.histplot(data=df_filt, x="imdbRating", kde=True, ax=ax)

# Adding labels and title to the plot
plt.xlabel('IMDB Rating')
plt.ylabel('Density')
plt.title('Distribution of IMDB Ratings')

# Displaying the plot
plt.show()

Der Plot zeigt die Verteilung der IMDB-Bewertungen für eine bestimmte Datenmenge. Die x-Achse zeigt die möglichen Bewertungen von 0 bis 10, und die y-Achse zeigt die Dichte, also wie häufig eine bestimmte Bewertung vorkommt. Die blaue Kurve ist eine Dichteschätzung, die eine geglättete Version der Verteilung darstellt. Die meisten Filme haben eine mittlere bis hohe Bewertung mit einem auffallendem Peak bei ca. 6.3. Die nachfolgende Untersuchung schauen sich das Zustandekommen der Bewertungen etwas genauer an.

Als erste denkbare Dimension wäre ein Einfluss des Filmgenre auf die Bewertung des Films.

Gibt es besonders gut bewertete Genres?

In [ ]:
# Counting the number of movies in each IMDB rating category and sorting them in ascending order
value_counts = df['imdbRating'].value_counts().sort_index()

# Printing the value counts of each IMDB rating category
value_counts
Out[ ]:
imdbRating
1.2    1
1.5    3
1.6    7
1.7    6
1.8    6
      ..
9.2    9
9.3    3
9.4    2
9.5    2
9.6    1
Name: count, Length: 83, dtype: int64
In [ ]:
# Counting the number of movies in each genre category and sorting them in descending order
genre_value_counts = df['genre'].value_counts()
genre_value_counts = genre_value_counts.sort_values(ascending=False)

# Displaying the top 10 genres with highest number of movies
genre_value_counts.head(10)
Out[ ]:
genre
Drama                     1717
Comedy                    1120
Comedy, Drama              859
Drama, Romance             741
Comedy, Drama, Romance     720
Comedy, Romance            563
Horror                     449
Action, Crime, Drama       413
Horror, Thriller           384
Documentary                342
Name: count, dtype: int64

Violin Plot of IMDB Ratings by Genre (Top 10 by occurrence in Dataset)

In [ ]:
# Counting the number of movies in each genre category and sorting them in descending order
value_counts = df['genre'].value_counts()

# Selecting the top 10 genres based on number of movies
top_genres = value_counts.head(10).index.tolist()

# Filtering the dataset to include only movies with top 10 genres
df_top_genres = df[df['genre'].isin(top_genres)]

# Creating a violin plot to show the distribution of IMDB ratings for each top genre
fig, ax = plt.subplots(figsize=(20, 10))
sns.violinplot(x="genre", y="imdbRating", data=df_top_genres, ax=ax, showmedians=True)

# Adding labels and title to the plot
plt.xlabel('Genre')
plt.ylabel('IMDB Rating')
plt.title('IMDB Ratings by Genre (Top 10 by occurence in Dataset)')

# Rotating the x-axis labels to prevent overlap
for item in ax.get_xticklabels():
    item.set_rotation(45)

plt.show()

Der Plot zeigt die Verteilung der IMDB-Bewertungen für die 10 häufigsten Genres in der Datenmenge. Die x-Achse zeigt die verschiedenen Genres, und die y-Achse zeigt die möglichen Bewertungen von 0 bis 10. Die Violinen, zeigen die Dichte der Bewertungen für jedes Genre an. Die weißen Punkte sind die Mittelwerte.

Eine mögliche Interpretation des Plots ist, dass Dokumentarfilme tendenziell höhere Bewertungen haben als andere Genres, mit einem Mittelwert von etwa 7.5 und einer schmalen Verteilung. Horror- und Komödienfilme haben dagegen tendenziell niedrigere Bewertungen, mit einem Mittelwert um 6 und einer breiten Verteilung. Dies könnte darauf hindeuten, dass diese Genres mehr subjektive oder polarisierende Meinungen hervorrufen. Die anderen Genres haben allgemein geringere Verteilungswerte was sich in der Breite der Violinen bemerkbar macht.

Hat das Jahr der Filmveröffentlichung einen Einfluss auf die Bewertung? Sind ältere Filme bei Liebhabern ebentuell beliebter, was eine bessere Bewertung dieser als Folge hat?

Plotting the Mean IMDB Rating by Year

In [ ]:
# Filtering out the rows where imdbRating is not available and year is between 1945 and 2016
#PrePro
df_mean = df[df['imdbRating'].notna()]
df_mean = df_mean.where(df_mean["year"]>=1945)
df_mean = df_mean.where(df_mean["year"]<=2016)

# Grouping the dataframe by year and computing the mean of imdbRating for each year
df_mean = df_mean.groupby('year')['imdbRating'].mean().reset_index()

# Create a line plot to visualize the trend of mean imdbRating over time
fig, ax = plt.subplots(figsize=(20, 10))
sns.lineplot(x="year", y="imdbRating", data=df_mean, ax=ax)

# Add labels and set the x-axis tick marks and labels
plt.xlabel('Year')
plt.ylabel('IMDB Rating Mean')
plt.title('IMDB Ratings Mean by Year')
xticks = range(int(df_mean['year'].min()), int(df_mean['year'].max()) + 5, 4)
ax.set_xticks(xticks)
ax.set_xticklabels(xticks)

plt.show()

Der Plot zeigt den Trend der durchschnittlichen IMDB-Bewertung für Filme, die zwischen 1945 und 2015 veröffentlicht wurden. Die x-Achse zeigt die Jahre, und die y-Achse zeigt die durchschnittliche Bewertung vom Minimum des jährlichen Durchschnitts bis zum Maximum. Die blaue Linie symbolisiert den Mittelwert für das jeweilige Jahr.

Eine mögliche Interpretation ist, dass die durchschnittliche IMDB-Bewertung im Laufe der Zeit leicht gesunken ist, mit einigen Schwankungen z.B. in den 60er Jahren. Die höchste durchschnittliche Bewertung wurde 1949 erreicht, mit etwa 7,4. Die niedrigste durchschnittliche Bewertung wurde 2009 erreicht, mit etwa 6,3. Dies könnte darauf hindeuten, dass die Qualität oder die Erwartungen der Filme sich im Laufe der Zeit verändert haben. Es könnte aber auch andere Faktoren geben, die die Bewertungen beeinflussen, wie zum Beispiel die Anzahl oder die Auswahl der Filme pro Jahr.

In [ ]:
fig, ax = plt.subplots(figsize=(20, 10))

# Create the regression plot
sns.regplot(x="year", y="imdbRating", data=df_mean, ax=ax)

# Add labels
plt.xlabel('Year')
plt.ylabel('IMDB Rating Mean')
plt.title('IMDB Ratings Mean by Year')

# Set the x-axis ticks and tick labels
xticks = range(int(df_mean['year'].min()), int(df_mean['year'].max()) + 5, 4)
ax.set_xticks(xticks)
ax.set_xticklabels(xticks)

# Rotate the x-axis tick labels
for item in ax.get_xticklabels():
    item.set_rotation(90)

# Display the plot
plt.show()

EXKURS

Weitere Untersuchungen sind unter crawlings_scripts zu finden. Da der vorhandene Datensatz nur wenige Daten zu sehr alten Filmen liefert, werden dort alte Filme direkt von der imdb-Seite gecrawlt. Insbesondere wurden Daten aus der ersten Hälfte des 20. Jahrhunderts gecrawlt. Dort kann man sehen, wie sich der imdb-Score vor den hier gezeigten Jahren entwickelt hat.

Der Plot zeigt den Trend der durchschnittlichen IMDB-Bewertung für Filme.. Die x-Achse zeigt die Jahre, und die y-Achse zeigt die durchschnittliche Bewertung. Die blaue Linie ist eine Regressionslinie, die die beste Anpassung an die Datenpunkte darstellt. Dies ist im Endeffekt nur eine andere Darstellung der obigen Linie.

Plotting the Number of Top 250 Movies by Year

In [ ]:
# Create a DataFrame of the top 250 movies by IMDB rating
df_top_250 = df.nlargest(250, 'imdbRating')

# Convert the year column to integers
df_top_250['year'] = df_top_250['year'].astype(int)

# Create a list of years to plot
years = range(int(df['year'].min()), int(df['year'].max())+1)

# Create a DataFrame with year as the index and count of movies as the values
df_years = pd.DataFrame({'year': years})
df_years['count'] = 0
df_years = df_years.set_index('year')

# Count the number of movies in each year
for year, group in df_top_250.groupby(['year']):
    df_years.loc[year, 'count'] = len(group)

# Plot the bar chart
df_years['count'].plot(kind='bar', figsize=(15, 5))
plt.xlabel('Year')
plt.ylabel('Number of Movies')
plt.title('Top 250 Movies by imdbRating per Year')
plt.gca().xaxis.set_major_locator(plt.MultipleLocator(5))
plt.show()

Der Plot zeigt die Anzahl der Filme, die zu den Top 250 Filmen nach IMDB-Bewertung gehören. Die x-Achse zeigt die Jahre, und die y-Achse zeigt die Anzahl der Filme. Die blauen Balken sind die Anzahl der Filme pro Jahr. Hier sieht man aber, dass die Top 250 Filme eher aktuellere Filme sind. Dies steht im Kontrast zu unserem vorherigen Plot. Eine mögliche Erklärung ist, dass die Filme, die früher veröffentlicht wurden, eine kleinere oder selektivere Gruppe von Nutzern hatten, die sie bewertet haben. Diese Nutzer könnten eher dazu neigen, Filme zu bewerten, die sie sehr gut finden, und Filme zu ignorieren, die sie nicht mögen oder nicht kennen. Dies könnte zu einem höheren Mittelwert der Bewertungen führen. Die Filme, die später veröffentlicht wurden, könnten eine größere oder diversere Gruppe von Nutzern haben, die sie bewertet haben. Diese Nutzer könnten eher dazu neigen, Filme zu bewerten, die sie sowohl gut als auch schlecht finden, oder Filme, die sie zufällig gesehen haben. Dies könnte zu einem niedrigeren Mittelwert der Bewertungen führen.

Creating an interactive bar plot of Top 250 Movies by Year using Plotly Express

In [ ]:
import plotly.express as px

# Create a bar chart with 'year' on the x-axis and 'imdbRating' on the y-axis
# Use the 'color' parameter to color-code the bars by 'imdbRating'
# Use the 'hover_data' parameter to include 'imdbVotes' as additional information when hovering over the bars
# Use the 'hover_name' parameter to display the 'imdbVotes' value when hovering over the bars
# Set the chart title
fig = px.bar(df_top_250, x='year', y='imdbRating', color='imdbRating',
             hover_data=['imdbVotes'],
             hover_name='imdbVotes',
             title="Top 250 movies distributed by year")

# Use the 'update_traces' method to add 'title' as an additional text to display when hovering over the bars
fig.update_traces(
                  hovertext=df_top_250['title'])

# Use the 'update_layout' method to hide the y-axis tick labels
fig.update_layout(
    yaxis=dict(
        showticklabels=False
    )
)

# Show the chart
fig.show()

Der Plot zeigt die Verteilung der Top 250 Filme nach IMDB-Bewertung über die Jahre. Die x-Achse zeigt die Jahre, und die y-Achse zeigt die IMDB-Bewertung von 0 bis 10. Die Balken sind nach der IMDB-Bewertung farbcodiert, wobei dunklere Farben höhere Bewertungen anzeigen. Wenn man mit der Maus über die Balken fährt, sieht man zusätzliche Informationen wie den Titel, die Anzahl der IMDB-Stimmen und den Wert der IMDB-Bewertung für jeden Film. Da einige der Filme sehr wenige Bewertungen haben, werden im nachfolgendem Filme <25000 Bewertungen ausgefiltert.

Plotting Top Movies by Year with a Minimum Number of Votes

In [ ]:
import plotly.express as px

# Select the top 250 movies by imdbRating
df_top_250 = df.nlargest(250, 'imdbRating')

# Convert year to integer
df_top_250['year'] = df_top_250['year'].astype(int)

# Filter out movies with less than 25000 votes
df_top_250 = df_top_250[df_top_250["imdbVotes"] >= 25000]

# Create a bar chart with year on x-axis, imdbRating on y-axis, and color-coded by imdbRating
fig = px.bar(df_top_250, x='year', y='imdbRating', color='imdbRating',
             hover_data=['imdbVotes'], hover_name='imdbVotes',
             title="Top movies distributed by year (Real popular movies by no of votes)")

# Add movie title to hovertext
fig.update_traces(hovertext=df_top_250['title'])

# Remove y-axis tick labels
fig.update_layout(yaxis=dict(showticklabels=False))

# Show the plot
fig.show()

Um eine Verbindung der Genre-Bewertung und der Jahresbetrachtung zu erstellen, wird nun der oben bereits dargestellte Scatter-Plot auf Genres aufgeteilt.

Analyzing IMDB Ratings by Genre and Year

In [ ]:
import scipy

# Get the top 10 most common genres
genre_counts = df["genre"].value_counts().head(10)
genres = genre_counts.index.tolist()

# Create a grid of subplots for each genre
fig, ax = plt.subplots(5, 2, figsize=(20, 30), sharex=True, sharey=True)
ax = ax.flatten()

# Loop through each genre and plot its mean IMDb rating over time
for i, genre in enumerate(genres):
    # Filter the data to only include rows for the current genre
    df_genre = df[df["genre"] == genre]
    
    # Filter out rows with missing IMDb ratings and limit the year range
    df_mean = df_genre[df_genre['imdbRating'].notna()]
    df_mean = df_mean.where(df_mean["year"]>=1945)
    df_mean = df_mean.where(df_mean["year"]<=2016)
    
    # Calculate the mean IMDb rating for each year
    df_mean = df_mean.groupby('year')['imdbRating'].mean().reset_index()
    
    # Create a scatter plot of the mean ratings over time
    sns.scatterplot(x="year", y="imdbRating", data=df_mean, ax=ax[i])
    
    # Add a red line to represent the linear regression line
    slope, intercept, r_value, p_value, std_err = scipy.stats.linregress(df_mean["year"], df_mean["imdbRating"])
    x = df_mean["year"]
    y = slope * x + intercept
    ax[i].plot(x, y, color="red")

    # Set the subplot title and axis labels
    ax[i].set_title(genre)
    if i == 8 or i == 9:
        ax[i].set_xlabel("Year")
    if i == 0 or i == 2 or i == 4 or i == 6 or i == 8:
        ax[i].set_ylabel("IMDB Rating Mean")

# Adjust the layout and display the plot
plt.tight_layout()
plt.show()

Der Plot zeigt die Verteilung der durchschnittlichen IMDB-Bewertung für die 10 häufigsten Genres in der Datenmenge über die Jahre. Die x-Achse zeigt die Jahre, und die y-Achse zeigt die durchschnittliche Bewertung. Die blauen Punkte sind die Mittelwerte für jedes Jahr, und die roten Linien sind die Regressionslinien, die den Trend anzeigen. Eine mögliche Interpretation des Plots ist, dass die meisten Genres einen negativen Zusammenhang zwischen dem Jahr und der durchschnittlichen IMDB-Bewertung zeigen. Dieser Trend war auch vorhin schon auf alle Genres bezogen zu sehen. Interessant ist, dass es kein einziges Genre unter den 10 gibt, welches über die Jahre eine steigende Trendlinie hat. Der einzige "Ausreißer" ist das Genre Dokumentarfilm, das einen sehr schwachen oder keinen Zusammenhang zwischen dem Jahr und der durchschnittlichen IMDB-Bewertung zeigt. Dies könnte darauf hindeuten, dass Dokumentarfilme eine konstante oder stabile Qualität oder Beliebtheit haben, oder dass sie weniger von den Veränderungen oder Trends in der Filmindustrie beeinflusst werden.

Wir haben festgestellt, dass die meisten Genres einen negativen Trend aufweisen, mit Ausnahme von Dokumentarfilmen. Genre-unabhängig ist der Trend ebenfalls negativ. Eine mögliche Frage, die sich daraus ergibt, ist, ob es einen Zusammenhang zwischen der Anzahl der IMDB-Stimmen und der IMDB-Bewertung gibt. Das heißt, ob Filme mit mehr Stimmen tendenziell höhere oder niedrigere Bewertungen haben als Filme mit weniger Stimmen

Scatter Plot and Correlation of IMDB Votes and Ratings

In [ ]:
# Create a figure and axis for the plot
fig, ax = plt.subplots(figsize=(20, 10))

# Create a scatter plot of imdbVotes vs imdbRating
sns.scatterplot(x="imdbVotes", y="imdbRating", data=df, ax=ax)

# Calculate the correlation coefficient between imdbVotes and imdbRating
correlation_coefficient = df['imdbVotes'].corr(df['imdbRating'])

# Create a regression plot of imdbVotes vs imdbRating
sns.regplot(x="imdbVotes", y="imdbRating", data=df, ax=ax)

# Add text to the plot indicating the correlation coefficient
text = "Correlation coefficient: {:.2f}".format(correlation_coefficient)
ax.text(0.05, 0.95, text, transform=ax.transAxes, verticalalignment='top')

# Set the x and y axis labels and plot title
plt.xlabel('IMDB Votes')
plt.ylabel('IMDB Rating')
plt.title('IMDB Votes vs IMDB Rating')

# Show the plot
plt.show()

Ein Korrelationskoeffizient von 0,19 bedeutet, dass es einen schwachen positiven Zusammenhang zwischen den IMDB-Stimmen und der IMDB-Bewertung gibt. Das heißt, je mehr Stimmen ein Film hat, desto höher ist tendenziell seine Bewertung, aber der Effekt ist nicht sehr stark, worauf die 0,19 hindeutet. Ein perfekter Zusammenhang wäre die 1. Ganz klar zu sehen ist aber, dass im rechten Bereich des Plots fast nurnoch vergleichsweise gut bewertete Filme zu sehen sind. Dies zeigt, dass Filme, welche große Aufmerksamkeit auf der Filmbewertungsseite erlangt haben, oftmals eine positive Tendenz in der Bewertung aufweisen. Zur näheren Betrachtung dieser Filme folgt ein interaktiver Plot, auf welchem zu sehen ist, welche Filme dies sind.

Scatter Plot of IMDB Votes vs IMDB Rating

In [ ]:
# Creating a scatter plot using the 'px.scatter()' function
fig = px.scatter(x=df["imdbVotes"],
                 y=df["imdbRating"],
                 hover_data=[df["title"], df["imdbRating"], df["year"]])

# Updating the layout of the scatter plot using the 'update_layout()' function.

fig.update_layout(
    title="IMDB Votes vs IMDB Rating",
    xaxis_title="IMDB Votes",
    yaxis_title="IMDB Rating",
    font=dict(size=10),
    width=1000,
    height=800
)

# Displaying the scatter plot using the 'show()' function.
fig.show()

Data preprocessing steps for the "country" column

In [ ]:
#PrePro
#Dropping rows with missing values in the "country" column
df = df.dropna(subset=['country'])
#Converting all country names to lowercase, removing leading/trailing whitespaces,
#and splitting countries listed in a single row into a list of individual countries
df['country'] = df['country'].str.lower().str.strip().str.split(',')
#Sorting the list of countries for each movie in alphabetical order
df['country'] = df['country'].apply(lambda x: sorted(x))
#Joining the list of individual countries back into a single string with commas separating them
df['country'] = df['country'].apply(lambda x: ','.join(x))

Visualizing the Average IMDB Rating per Country for the Top 30 Countries

In [ ]:
# Get the top 30 countries by value counts
df_country = df['country'].value_counts().head(30)

# Store the value counts in a separate dataframe
occurece_df = df_country

# Get a list of the top countries
top_countries = df_country.index.tolist()

# Filter the original dataframe to only include rows with countries in the top countries list
df_top_countries = df[df['country'].isin(top_countries)]

# Group by country and calculate the mean imdbRating for each country
df_country = df_top_countries.groupby('country')['imdbRating'].mean().reset_index()

# Join the occurence_df to add the value counts as a new column
df_country = df_country.join(occurece_df, on=df_country["country"] , how='left', lsuffix='_left', rsuffix='_right')
# Sort the resulting dataframe by value counts in descending order
df_country.sort_values(by="country",inplace=True,ascending=False)

# Set the figure size for the plot
plt.figure(figsize=(20, 10))

# Create a barplot of average imdbRating by country using seaborn
sns.barplot(x="imdbRating", y="country", data=df_country,palette=reversed(sns.cubehelix_palette(n_colors=len(df_country))))

# Set the x and y labels and title for the plot
plt.xlabel("Average IMDB Rating")
plt.ylabel("Country")
plt.title("Average IMDB Rating per Country (Top 30), ordered by no of samples")

# Show the plot
plt.show()

Der Plot ist ein Balkendiagramm, das die durchschnittliche IMDB-Bewertung pro Land für die 30 wichtigsten Länder, geordnet nach der Anzahl der Proben, zeigt. Die x-Achse zeigt die durchschnittliche IMDB-Bewertung und die y-Achse zeigt das Land. Die Darstellung ist in absteigender Reihenfolge nach der Anzahl der Werte sortiert. Insgesamt deuten die Daten darauf hin, dass die Anzahl der von einem Land produzierten Filme nicht unbedingt mit der Qualität dieser Filme korreliert und dass einige Länder mit einer kleineren Filmindustrie Filme mit einer höheren Durchschnittsbewertung produzieren. Darüber hinaus kann die Zusammenarbeit zwischen Ländern zu qualitativ besseren Filmen führen als die Produktion durch ein einzelnes Land. Die Soviet Union, gefolgt von Polen hat in den zugrundeliegenden Daten sehr gut abgeschnitten. In der Soviet Union gibt es nur alte Filme, da diese im Jahr 1991 aufgelöst wurde. Diese Beobachtung deckt sich mit den Ergebnissen aus der Regressionsgeraden.

In [ ]:
df["awards"].value_counts()
Out[ ]:
awards
1 nomination.                                                1666
1 win.                                                        881
2 nominations.                                                682
1 win & 1 nomination.                                         608
3 nominations.                                                381
                                                             ... 
Nominated for 2 Oscars. Another 7 wins & 5 nominations.         1
Won 7 Oscars. Another 63 wins & 77 nominations.                 1
Nominated for 1 Oscar. Another 10 wins & 22 nominations.        1
Nominated for 5 Oscars. Another 16 wins & 69 nominations.       1
Nominated for 2 Oscars. Another 8 wins & 16 nominations.        1
Name: count, Length: 2728, dtype: int64

Die Spalte "Auszeichnungen" enthält String-Werte, die die Anzahl der Nominierungen und Gewinne für jeden Film beschreiben. Um die Spalte visualisieren zu können, müssen wir diese String-Werte in Integer-Werte umwandeln, die die Gesamtzahl der Nominierungen und Gewinne darstellen. Dazu definieren wir eine Funktion extract_noms_and_wins, die eine Zeichenkette als Eingabe nimmt und die Summe aller in der Zeichenkette gefundenen zahlen zurückgibt. Anschließend wenden wir diese Funktion auf die Spalte 'awards' an, um eine neue Spalte 'nomsandwins' zu erstellen, die die Gesamtzahl der Nominierungen und Gewinne für jeden Film enthält.

Extracting the Total Number of Nominations and Wins from Awards Column

In [ ]:
# Import regular expression module
import re

# Define a function to extract the total number of nominations and wins from a string
def extract_noms_and_wins(string):
    # Check if the input is a string
    if not isinstance(string, str):
        return 0
    # Use regex to find all integers in the string
    integers = re.findall(r'\d+', string)
    # Convert the list of strings to a list of integers
    integers = [int(i) for i in integers]
    # Return the sum of all integers in the list
    return sum(integers)

# Apply the function to the 'awards' column and store the result in a new column 'nomsandwins'
df['nomsandwins']= df['awards'].apply(extract_noms_and_wins)

Um neben den Nutzerbewertungen auch andere Maßstäbe für den Erfolg eines Films zu berücksichtigen, verlagern wir unseren Schwerpunkt von der imdb-Bewertung auf die Anzahl der gewonnenen und nominierten Preise für jeden Film. Anstelle der imdb-Bewertung verwenden wir die zuvor erstellte Spalte "nomsandwins", die die Gesamtzahl der Nominierungen und Gewinne für jeden Film enthält.

Visualizing the Posters of the Top 10 Movies by Number of Won and Nominated Prizes

In [ ]:
# Import urllib module
import urllib

# Remove rows with missing values in the 'poster' column
df_removed = df.dropna(subset=['poster'])

# Get the top 10 films based on the nomsandwins column
top_10 = df_removed.nlargest(11, 'nomsandwins')
top_10.drop_duplicates(inplace=True, subset=["title"])

# Create a list of the URLs for the top 10 films
poster_urls = top_10['poster'].tolist()

# Download the images and store them as arrays
images = []
for url in poster_urls:
    with urllib.request.urlopen(url) as url:
        image = plt.imread(url, format='jpeg')
        images.append(image)

# Create a 2x5 grid of subplots to display the images
fig, ax = plt.subplots(2, 5, figsize=(20, 10))
for i, image in enumerate(images):
    # Display the image in the subplot
    ax[i//5, i%5].imshow(image)
    # Turn off the axis for the subplot
    ax[i//5, i%5].axis('off')
   
    # Add text to display the sum of nominations and wins below each image
    ax[i//5, i%5].text(140, -5, "Sum: "+ str(top_10.iloc[i]['nomsandwins']), 
                      ha='center', fontsize=15, color='black', fontweight='bold')
    # Add text to display the title of the movie above each image
    ax[i//5, i%5].text(140, 490, top_10.iloc[i]['title'].split(":")[0].strip(), 
                      ha='center', fontsize=15, color='black', fontweight='bold')

# Adjust the spacing between subplots
plt.subplots_adjust(hspace=0.3)

# Add a title for the entire figure
plt.suptitle("Top Movies by number of Won and Nominated Prices:", fontweight='bold', fontsize=16, y=0.93)
Out[ ]:
Text(0.5, 0.93, 'Top Movies by number of Won and Nominated Prices:')

Dieser Code generiert eine visuelle Darstellung der Top-10-Filme auf der Grundlage der Gesamtzahl der Nominierungen und Gewinne, mit ihren Postern, Titeln und der Gesamtzahl der Nominierungen und Gewinne angezeigt.

Visualizing the Number of Won and Nominated Prizes for the Top 10 Movies

In [ ]:
# Create a barplot of the nomsandwins column
fig, ax = plt.subplots(figsize=(10, 5))
ax.barh(y=top_10['title'], width=top_10['nomsandwins'])

# Set the x and y labels for the plot
ax.set_ylabel("Title")
ax.set_xlabel("Number of Awards won or nominated")

# Adjust the layout of the plot
plt.tight_layout()

# Show the plot
plt.show()

Dieser Code erstellt ein horizontales Balkendiagramm, das die Gesamtzahl der Nominierungen und Gewinne für die 10 besten Filme anzeigt. Die y-Achse des Diagramms zeigt die Titel der Top-10-Filme, die x-Achse zeigt die Gesamtzahl der Nominierungen und Gewinne. Auffällig ist der große Vorsprung des Films "12 Years a Slave" vor allen anderen Filmen im Datensatz.

Visualizing the Average Number of Nominated or Won Prizes per Country for the Top 30 Countries

In [ ]:
# Get the top 30 countries by value counts
df_country = df['country'].value_counts().head(30)

# Store the value counts in a separate dataframe
occurece_df = df_country

# Get a list of the top countries
top_countries = df_country.index.tolist()

# Filter the original dataframe to only include rows with countries in the top countries list
df_top_countries = df[df['country'].isin(top_countries)]

# Group by country and calculate the mean nomsandwins for each country
df_country = df_top_countries.groupby('country')['nomsandwins'].mean().reset_index()

# Join the occurece_df to add the value counts as a new column
df_country = df_country.join(occurece_df, on=df_country["country"] , how='left', lsuffix='_left', rsuffix='_right')

# Sort the resulting dataframe by value counts in descending order
df_country.sort_values(by="country",inplace=True,ascending=False)

# Set the figure size for the plot
plt.figure(figsize=(20, 10))

# Create a barplot of average nomsandwins by country using seaborn
sns.barplot(x="nomsandwins", y="country", data=df_country,palette=reversed(sns.cubehelix_palette(n_colors=len(df_country))))

# Set the x and y labels and title for the plot
plt.xlabel("Average Prices nominated or won")
plt.ylabel("Country")
plt.title("Average Prices nominated or won per Country (Top 30), ordered by no of samples")

# Show the plot
plt.show()

Dieser Code erstellt ein horizontales Balkendiagramm, das die durchschnittliche Anzahl der Nominierungen und Gewinne pro Land für die 30 führenden Länder anzeigt. Die y-Achse des Diagramms zeigt die Namen der 30 besten Länder, während die x-Achse die durchschnittliche Anzahl der Nominierungen und Gewinne anzeigt. Hier sticht vorallem die Zusammenarbeit von UK und USA ins Auge, da sie die höchste durchschnittliche Anzahl von Nominierungen und Siegen haben. Aber auch Spanien, was bereits im vorherigen Plot ein gutes Ergebnis erzielen konnte hat hier ein gutes Ergebnis erzielen können.

Nun wird der Datensatz noch auf die Handlungen innerhalb der Filme durchsucht. Der Datensatz wird anhand der Fullplot-Spalte, die eine textliche Beschreibung der Filmhandlung enthält, nach Handlungssträngen innerhalb der Filme durchsucht. Um die Handlungen in den am höchsten bewerteten Filmen zu extrahieren, wird der Inhalt dieser Textspalte statistisch analysiert und in einer Wordcloud visualisiert. Eine Wordcloud zeigt die am häufigsten vorkommenden Wörter an, wobei die Größe der Wörter davon abhängt, wie oft sie im Text verwendet werden.

Creating a Word Cloud of the Full Plot for the Top 5000 Films by IMDB Rating

In [ ]:
# Import necessary modules
from wordcloud import WordCloud, STOPWORDS

# Add additional stopwords to the set of stopwords
STOPWORDS.add("one")
STOPWORDS.add("life")
STOPWORDS.add("live")
STOPWORDS.add("will")

# Get the top 5000 films based on imdbRating
df_top_5000 = df.nlargest(5000, 'imdbRating')

# Remove rows with missing values in the 'fullplot' column
df_top_5000 = df_top_5000.dropna(subset=['fullplot'])
#PrePro
# Concatenate all fullplot strings into one long string
text = ' '.join(df_top_5000['fullplot'].tolist())

# Create a set of stopwords
stopwords = set(STOPWORDS)

# Generate a word cloud from the text
wordcloud = WordCloud(stopwords=stopwords, background_color='white',
                      width=800, height=800, max_words=300,
                      min_font_size=10).generate(text)

# Set the figure size and facecolor for the plot
plt.figure(figsize=(8, 8), facecolor=None)

# Display the word cloud in the plot
plt.imshow(wordcloud, interpolation="bilinear")

# Turn off the axis for the plot
plt.axis("off")

# Add a title for the plot
plt.title("Word Cloud of Top 5000 Films by imdb Score\n", fontsize=20)

# Adjust the layout of the plot
plt.tight_layout(pad=0)
plt.show()

Die Wordcloud für die 5000 besten Filme, sortiert nach IMDb-Score, enthält hauptsächlich positive Wörter. Dies ist etwas überraschend. Werden die Handlungen von Thrillern, Actionfilmen und Krimis zunehmend mit positiven Begriffen beschrieben? Sind diese Genres in den 5000 am besten bewerteten Filmen nicht so stark vertreten? Eventuell liegt es auch daran, dass Gefühle und positive Dinge in fast allen Filmen zu finden sind, welche gut beim Zuschauer ankommen. Um das genauer anzuschauen, werden im folgenden die Wordclouds für Filme pro Genre erstellt

Creating Word Clouds for the Full Plot of the Top 10 Genres of the Top Films by IMDB Rating

In [ ]:
from collections import Counter

# Remove rows with missing values in the 'fullplot', 'genre', and 'imdbRating' columns
df_filtered = df.dropna(subset=['fullplot', 'genre',"imdbRating"])

#Remove multi genre movies
df_filtered['genre'] = df_filtered['genre'].str.split(',', expand=True)[0]

# Strip leading and trailing whitespace from the 'genre' column
df_filtered['genre'] = df_filtered['genre'].str.strip()

# Select only the 'fullplot', 'genre', and 'imdbRating' columns and sort by imdbRating in descending order
df_filtered = df_filtered[['fullplot', 'genre',"imdbRating"]].sort_values('imdbRating', ascending=False)

# Get the value counts for each genre
value_counts = df_filtered['genre'].value_counts()

# Get a list of the top 10 genres
top_genres = value_counts.head(10).index.tolist()
avg_imdb_score = df_filtered.groupby('genre')['imdbRating'].mean()
# Create a 5x2 grid of subplots to display the word clouds
fig, ax = plt.subplots(5, 2, figsize=(20, 30))
ax = ax.ravel()
for i, genre in enumerate(top_genres):
    # Get the texts for the current genre
    genre_text = df_filtered[df_filtered['genre'].str.contains(genre)]['fullplot'].str.cat(sep=' ')

    # Create a word cloud for the current genre
    wordcloud = WordCloud(width=800, height=800, background_color='white').generate(genre_text)

    # Display the word cloud in the subplot
    ax[i].imshow(wordcloud, interpolation='bilinear')
    # Turn off the axis for the subplot
    ax[i].axis('off')
    # Add a title for the subplot
    ax[i].set_title(f"{genre} (n={value_counts[genre]}, avg IMDb score={avg_imdb_score[genre]:.2f})")

# Add a title for the entire figure
plt.suptitle("Word clouds of top 10 genres of movies by imdb Score", fontsize=20, y=1.05)

# Adjust the layout of the plot
plt.tight_layout()

# Show the plot
plt.show()
C:\Users\swt4fe\AppData\Local\Temp\ipykernel_25020\3592765647.py:7: SettingWithCopyWarning:


A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

C:\Users\swt4fe\AppData\Local\Temp\ipykernel_25020\3592765647.py:10: SettingWithCopyWarning:


A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

In dieser Visualisierung sehen Sie Wortwolken für die Top-Filme eines jeden Genres. Die Wörter, die in jeder Wortwolke erscheinen, sind repräsentativ für die Themen und Gegenstände, die in diesem Genre häufig vorkommen. In der Wortwolke "Horror" finden Sie zum Beispiel Wörter wie "Mord", "Nacht" oder "Zombie", während Sie in der Wortwolke "Drama" Wörter wie "Liebe", "Familie" oder "Mutter" finden können. Wenn du dir die einzelnen Wortwolken genau ansiehst, wirst du einige Gemeinsamkeiten zwischen den Genres feststellen. Zum Beispiel taucht das Wort "finden" in fast allen Wortwolken auf, was darauf hindeutet, dass in vielen Filmen Figuren auf der Suche nach etwas sind. Es gibt jedoch auch einige unerwartete Wörter, die auftauchen, wie z. B. "Vater" in der Wortwolke Abenteuer. Dies deutet darauf hin, dass Vaterschaft ein häufiges Thema in Abenteuerfilmen ist.

Die Erstellung einer Wordcloud, die nur Substantive enthält, kann einen gezielteren Blick auf die Hauptthemen im Text ermöglichen. Substantive stehen oft für die Personen, Orte und Dinge, die in einer Geschichte oder einem Thema eine zentrale Rolle spielen. Wenn andere Wortarten wie Verben, Adjektive und Adverbien herausgefiltert werden, können die am häufigsten erwähnten Themen im Text leichter erkennt werden.

Extracting Nouns from the Full Plot Column

In [ ]:
import nltk
from nltk import word_tokenize
from nltk.tag import pos_tag
#PrePro
# Download necessary resources from nltk
nltk.download('punkt')
nltk.download('averaged_perceptron_tagger')

# Define a function to extract nouns from a text
def get_nouns(text):
    # Tokenize the text into words
    words = word_tokenize(text)
    # Tag the words with their part of speech
    tagged_words = pos_tag(words)
    # Extract the nouns from the tagged words
    nouns = [word for word, pos in tagged_words if pos in ['NN', 'NNS', 'NNP', 'NNPS']]
    # Return the list of nouns
    return nouns

# Create a copy of the original dataframe
df_nouns = df 

# Remove rows with missing values in the 'fullplot' column
df_nouns = df_nouns.dropna(subset=['fullplot'])

# Apply the get_nouns function to the 'fullplot' column and store the result in a new column 'fullplot_nouns'
df_nouns['fullplot_nouns'] = df_nouns['fullplot'].apply(get_nouns)
[nltk_data] Downloading package punkt to
[nltk_data]     C:\Users\swt4fe\AppData\Roaming\nltk_data...
[nltk_data]   Package punkt is already up-to-date!
[nltk_data] Downloading package averaged_perceptron_tagger to
[nltk_data]     C:\Users\swt4fe\AppData\Roaming\nltk_data...
[nltk_data]   Package averaged_perceptron_tagger is already up-to-
[nltk_data]       date!
C:\Users\swt4fe\AppData\Local\Temp\ipykernel_25020\2041100774.py:27: SettingWithCopyWarning:


A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

Creating a Word Cloud of the Nouns in the Full Plot for the Top 500 Films by IMDB Rating

In [ ]:
# Get the top 500 films based on imdbRating
df_nouns = df_nouns.nlargest(500, 'imdbRating')

# Concatenate all fullplot_nouns lists into one long string
text = ""
for ele in df_nouns["fullplot_nouns"]:
     text = text + " ".join(ele)

# Generate a word cloud from the text
wordcloud = WordCloud(stopwords=stopwords, background_color='white',
                      width=800, height=800, max_words=300,
                      min_font_size=10).generate(text)

# Set the figure size and facecolor for the plot
plt.figure(figsize=(8, 8), facecolor=None)

# Display the word cloud in the plot
plt.imshow(wordcloud, interpolation="bilinear")

# Turn off the axis for the plot
plt.axis("off")

# Add a title for the plot
plt.title("Word Cloud of Top 500 Films by imdb Score (only nouns) \n", fontsize=20)

# Adjust the layout of the plot
plt.tight_layout(pad=0)

# Show the plot
plt.show()

Exkurs

Basierend auf der Full-Plot Beschreibung des Films wird im weiteren Notebook fullplot_to_genre.ipynb eine Vorhersage der Genres durch die Handlungsbeschreibung implementiert.

Zusammenfassung¶

In diesem Data Exploration Notebook haben wir verschiedene Fragen untersucht, um Einblicke in die Bewertungen von Filmen auf IMDB zu gewinnen. Unter anderem haben wir folgende Fragen beantwortet:

  • Gibt es besonders gut bewertete Film Genres?
  • Sind ältere Filme beliebter als neuere?
  • Wie wirken sich das Veröffentlichungsjahr des Films und das Genre auf die Bewertungen aus?
  • Gibt es Länder, die Filme durchschnittlich besonders gut bewerten?

Unsere Analyse hat gezeigt, dass die Filmbewertungen im Laufe der Zeit tendenziell abgenommen haben. Dies könnte darauf hindeuten, dass Filme schlechter geworden sind, muss es aber nicht. Es ist auch möglich, dass die Menschen im Laufe der Jahre höhere Erwartungen an Filme hatten und sie daher durchschnittlich schlechter bewertet haben. Eine weiterführende Untersuchung von Filmen, die vor dem im Hauptdatensatz behandelten Zeitraum veröffentlicht wurden, hat jedoch gezeigt, dass der Trend nicht für Filme anhält, die vor 1945 veröffentlicht wurden. Es war sehr interessant zu sehen, dass die ersten Filme, die jemals von Menschenhand produziert wurden, im Durchschnitt auf IMDB keine sehr hohen Bewertungen erhalten haben. Es war auch interessant, diese Erkenntnisse zu gewinnen, indem ein eigen generierter Datensatz verwendet wurde. Durch die Verwendung eines maßgeschneiderten Datensatzes konnten wir gezielt die Informationen sammeln, die für unsere Untersuchung relevant waren, und so genauere und aussagekräftigere Ergebnisse erzielen.

Einen tieferen Einblick in das Thema Genre und insbesondere in die Beziehung zwischen Genre und Veröffentlichungsdatum kann man mit unserer interaktiven Webseite erlangen. Durch die Verwendung des Genre-Filters auf der Webseite konnten wir einige interessante Erkenntnisse über die “Hoch-Zeiten” bestimmter Genres gewinnen. Beispielsweise haben wir festgestellt, dass Horrorklassiker, die in den Top 20 basierend auf ihren IMDB-Bewertungen sind, fast ausschließlich im 20. Jahrhundert veröffentlicht wurden. Dies spricht auch für unsere Beobachtung, dass Horrorfilme im Laufe der Jahre an Qualität verloren haben könnten. Unsere interaktive Webseite bietet eine benutzerfreundliche Möglichkeit, diese und andere Erkenntnisse zu erkunden und zu vertiefen.

Wir haben auch festgestellt, dass Filme des Genres Dokumentarfilm am stetigsten bewertet wurden. Dies könnte daran liegen, dass sie auf Fakten basieren und daher weniger subjektiv beurteilt werden als andere Genres wie Horror oder Komödien.

Die Verteilung der IMDB-Ratings liegt zwischen 1 und 10, wobei die meisten Bewertungen zwischen 6.0 und 8.0 liegen. Im Violin-Plot haben wir breite Verteilungen für bestimmte Genres wie Horrorfilme gesehen, die auf einer subjektiven Grundlage beurteilt werden. Die Beurteilungen könnten auch mit Schauspielern oder Regisseuren zusammenhängen, aber diese Vermutung wurde in diesem Notebook nicht weiter untersucht.

Letztendlich lässt sich sagen, dass die IMDB-Bewertungen ein hilfreiches Tool sein können, um die Qualität von Filmen zu beurteilen. Es gibt jedoch auch Einschränkungen, da die Bewertungen subjektiv sind und von vielen Faktoren beeinflusst werden können.

Unsere Ergebnisse entsprechen unseren Erwartungen an diese Data Exploration. Wir hätten erwartet, dass in der Wordcloud der Top 5000 Filme mehrere Worte gesammelt worden wären, die auf Genres wie Horror, Action oder Crime schließen würden. Es war daher sinnvoll, Wordclouds zu erstellen, die nach Genre gruppiert sind.

Eine Untersuchung der Kommentare, die Filmfans optional zu ihren Bewertungen abgeben können, hat gezeigt, dass bereits mit einer Stichprobe von 50.000 gelabelten Kommentaren ein Sentiment-Analyse-Modell trainiert werden kann. Dafür kamen mehrere Architekturen in Frage, darunter neuronale Netze und Support Vector Machines. Durch die Anwendung von Sentiment-Analyse konnte ein umfassendes Preprocessing durchgeführt werden.